package statistics

import org.codehaus.groovy.grails.commons.ApplicationHolder as AH

import java.sql.Connection
import java.sql.Statement
import org.apache.log4j.Logger
import org.hibernate.Session
import org.hibernate.SessionFactory
import org.springframework.orm.hibernate3.SessionFactoryUtils

/**
 * simple tool to generate statistics and flush/optimize/clear the session and database from time to time
 *
 * User: wohlgemuth
 * Date: Feb 19, 2010
 * Time: 1:47:58 PM
 *
 */
class ImportStatistic {

  private Logger logger = Logger.getLogger("statistic.import")

  private static ImportStatistic instance

  private Session session = null

  private ImportStatistic() {
    try {
      logger.debug "creating new instance..."
      def ctx = AH.application.mainContext

      logger.debug "connecting to session factory..."
      SessionFactory sessionFactory = (SessionFactory) ctx.getBean("sessionFactory")

      logger.debug "connecting to session..."
      session = sessionFactory.currentSession

    }
    catch (Exception e) {
      e.printStackTrace()
      logger.error e.getMessage(), e
    }

  }

  static ImportStatistic getInstance() {

    if (instance == null) {
      instance = new ImportStatistic()
    }
    return instance
  }

  /**
   * we want to flush
   */
  boolean flush = true

  /**
   * do we enable statistics
   */
  boolean enable = true

  /**
   * do we allow reindexing
   */
  boolean reindex = true

  /**
   * enabling reindexing
   */
  boolean enableReindex = true

  /**
   * we want to provide batching
   */
  int flushBatchSize = 100

  /**
   * after how many inserts do we want to reindex the database
   */
  int reindexBatchSize = 10000

  /**
   * private counter for the flushing
   */
  private int flushCount = 0

  /**
   * private counter for the reindexing
   */
  private int reindexCount = 0

  /**
   * wenn did the batch start
   */
  private long startedFlushBatch

  /**
   * wenn did the batch start
   */
  private long startedReindexhBatch

  /**
   * increase the counters by one
   */
  private void increaseCount() {
    flushCount = flushCount + 1
    reindexCount = reindexCount + 1
  }

  /**
   * executes the flushing
   */
  public void flush() {
    logger.debug "flushing..."
    if (flush) {
	forceFlush()
    }
  }

  /**
   * forces the flushing of the session
   */
  public void forceFlush(){
      session.flush()
      session.clear()
      org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP.get().clear()
  }
  /**
   * executes the reindexing of the database
   */
  public void reindex() {
    if (reindex) {
      logger.debug "reindexing the database"
      Connection connection = session.connection()

      Statement statement = connection.createStatement()

      statement.execute("reindex table compound")
      statement.execute("reindex table dblinks")
      statement.execute("reindex table synonym")
      statement.execute("reindex table smiles")
      statement.execute("reindex table iupac")
      statement.execute("reindex table inchi_hash_key")

      statement.close()
    }
  }

  public void aquire() {
    try {
      if (enable) {
        if (flushCount == 0) {
          logger.debug "starting a new flush batch..."
          startedFlushBatch = System.currentTimeMillis()
        }
        if (reindexCount == 0) {
          logger.debug "starting a new reindex batch..."
          startedReindexhBatch = System.currentTimeMillis()
        }

        increaseCount()

        if (flushCount % flushBatchSize == 0) {
          long endedBatch = System.currentTimeMillis()
          long difference = endedBatch - startedFlushBatch

          flushCount = 0
          flush()

          logger.info "Statistic:import action:flush batchSize:${flushBatchSize} flush:${flush} reindex:${reindex}  time:${difference} avg:${difference / flushBatchSize}"
        }

        if (reindexCount % reindexBatchSize == 0) {
          long endedBatch = System.currentTimeMillis()
          long difference = endedBatch - startedReindexhBatch

          reindexCount = 0
          reindex()

          logger.info "Statistic:import action:reindex batchSize:${reindexBatchSize} flush:${flush} reindex:${reindex} time:${difference} avg:${difference / reindexBatchSize}"
        }

      }
    }
    catch (Exception e) {
      e.printStackTrace()
      logger.error e.getMessage(), e
    }

  }

}
